package service

import (
	"fmt"
	"choujiang/common/consts"
	"choujiang/common/db"
	"choujiang/common/models"
	"choujiang/common/utils"
	"strconv"
	"time"
)

const (
	RECOMMEND_GAME_KEY       = "BoxKey::leyouboxrecommendgame_"
	RECOMMEND_TO_RECEIVE_KEY = "BoxKey::leyouboxrecommendtoreceive_"
	RECOMMEND_RECENTLY_DATE  = "BoxKey::leyouboxrecentlydate_"
	USER_GAME_REWARD_KEY     = "BoxKey::leyouboxusergamereward_" //用户金币奖励值缓存
)

type CateGames struct {
	Id    int64        `json:"id"`
	Icon  string       `json:"icon"`
	Name  string       `json:"name"`
	Games []model.Game `json:"games"`
}

func GetGameList(plat, pageSize int, gameId string, userId int64) []model.Game {
	games := make([]model.Game, 0)
	box := new(model.Box)
	_, err := db.MysqlEngine.Where("name = ?", gameId).Get(box)
	if err != nil || box == nil {
		fmt.Printf("Get box err ---------%v", err)
		return games
	}
	ids := []int64{}
	gameBox := make([]model.GameBox, 0)
	err = db.MysqlEngine.Where("box_id=?", box.Id).Find(&gameBox)
	if err != nil || len(gameBox) < 1 {
		fmt.Printf("Get gamebox err ---------%v", err)
		return games
	} else {
		for i := 0; i < len(gameBox); i++ {
			ids = append(ids, gameBox[i].GameId)
		}
	}
	err = db.MysqlEngine.Where("status=?", 1).In("id", ids).In("platform", []int{0, plat}).Desc("order").Find(&games)
	if err != nil {
		fmt.Printf("GetGameList err:%+v\n", err)
	}

	for i := 0; i < len(games); i++ {
		games[i].Icon = utils.AddPrefix(games[i].Icon)
		games[i].Played = db.Mgo.EverPlayed(userId, games[i].GameId)
		games[i].Cover = utils.AddPrefix(games[i].Cover)
		games[i].QrCode = utils.AddPrefix(games[i].QrCode)
	}
	return games
}

func GetRecommendList(plat, pageSize int, gameId string, userId int64, needReward bool) []model.Game {
	games := make([]model.Game, 0)
	box := new(model.Box)
	_, err := db.MysqlEngine.Where("name = ?", gameId).Get(box)
	if err != nil || box == nil {
		fmt.Printf("Get box err ---------%v", err)
		return games
	}
	ids := []int64{}
	gameBox := make([]model.GameBox, 0)
	err = db.MysqlEngine.Where("box_id=?", box.Id).Find(&gameBox)
	if err != nil || len(gameBox) < 1 {
		fmt.Printf("Get gamebox err ---------%v", err)
		return games
	} else {
		for i := 0; i < len(gameBox); i++ {
			ids = append(ids, gameBox[i].GameId)
		}
	}
	fmt.Printf("ids is -----------%s", ids)
	if pageSize != 0 {
		err := db.MysqlEngine.Where("status=? and is_recommend=?", 1, 1).In("id", ids).In("platform", []int{0, plat}).Limit(5, 0).Desc("order").Find(&games)
		if err != nil {
			fmt.Printf("GetRecommendList err:%+v\n", err)
		}
	} else {
		err := db.MysqlEngine.Where("status=? and is_recommend=?", 1, 1).In("id", ids).In("platform", []int{0, plat}).Desc("order").Find(&games)
		if err != nil {
			fmt.Printf("GetRecommendList err:%+v\n", err)
		}
	}

	for i := 0; i < len(games); i++ {
		games[i].Icon = utils.AddPrefix(games[i].Icon)
		if needReward {
			games[i].Reward = CalculateReward(games[i], userId)
		}
	}
	return games
}

func CalculateReward(game model.Game, userId int64) int64 {
	var reward int64
	gameKey := USER_GAME_REWARD_KEY + game.GameId + strconv.FormatInt(userId, 10)
	exist := db.MainRedisClient.Exists(gameKey)
	if exist.Val() == 1 { //有缓存
		rewardKey := db.MainRedisClient.Get(gameKey)
		reward, _ = strconv.ParseInt(rewardKey.Val(), 10, 64)
	} else { //无缓存
		reward = db.Mgo.CalculateReward(game.GameId, userId, game.Reward)
		db.MainRedisClient.Set(gameKey, reward, time.Hour)
	}
	return reward
}

func GetRecommendNum(plat int) int {
	games := make([]model.Game, 0)
	err := db.MysqlEngine.Where("status=? and is_recommend=?", 1, 1).In("platform", []int{0, plat}).Desc("order").Find(&games)
	if err != nil {
		fmt.Printf("GetRecommendList err:%+v\n", err)
	}
	return len(games)
}

func GetBannerList(plat int) []model.Banner {
	games := make([]model.Banner, 0)
	err := db.MysqlEngine.Where("status=?", 1).In("platform", []int{0, plat}).Desc("order").Find(&games)
	if err != nil {
		fmt.Printf("GetBannerList err:%+v\n", err)
	}
	for i := 0; i < len(games); i++ {
		games[i].Icon = utils.AddPrefix(games[i].Icon)
	}
	fmt.Printf("GetBannerList :%+v\n", games)
	return games
}

func GetPlayedRecommend(user *model.User, gameId string) []string {
	games := GetRecommendList(0, 0, gameId, user.Id, false)
	fmt.Println("games info --------------", games)
	reSlice := make([]string, 0)
	if games != nil {
		for i := 0; i < len(games); i++ {
			if alreadyPlay(games[i].GameId, user.Id, gameId) {
				reSlice = append(reSlice, games[i].GameId)
			}
		}
	}
	return reSlice
}

func GetToReceiveRecommend(user *model.User, gameId string) []string {
	games := GetRecommendList(0, 0, gameId, user.Id, false)
	fmt.Println("games info --------------", games)
	reSlice := make([]string, 0)
	if games != nil {
		for i := 0; i < len(games); i++ {
			if toReceive(games[i].GameId, user.Id, gameId) {
				reSlice = append(reSlice, games[i].GameId)
			}
		}
	}
	return reSlice
}

func alreadyPlay(gameId string, userId int64, boxId string) bool {
	reBool := false
	key := RECOMMEND_GAME_KEY + gameId + utils.TodayUnix()
	if boxId != "leyoubox" {
		key = RECOMMEND_GAME_KEY + gameId + boxId
	}
	val := db.MainRedisClient.SIsMember(key, userId)
	if val.Val() {
		reBool = true
	}
	return reBool
}

func toReceive(gameId string, userId int64, boxId string) bool {
	reBool := false
	key := RECOMMEND_TO_RECEIVE_KEY + gameId + utils.TodayUnix()
	if boxId != "leyoubox" {
		key = RECOMMEND_TO_RECEIVE_KEY + gameId + boxId
	}
	val := db.MainRedisClient.SIsMember(key, userId)
	if val.Val() {
		reBool = true
	}
	return reBool
}

func GetGamesByPage(pageNo, pageSize, aType int) ([]model.Game, int) {
	hasMore := 0
	games := make([]model.Game, 0)
	curPageNo := (pageNo - 1) * pageSize
	nextCurPageNo := pageNo * pageSize
	if aType == 99 { //推荐游戏
		err := db.MysqlEngine.SQL("select * from game where status=? and is_recommend=? order by `order` desc limit ?,?", 1, 1, curPageNo, pageSize).Find(&games)
		if err != nil {
			fmt.Printf("GetGamesByPage err:%+v\n", err)
		}
		count := len(games)
		fmt.Println("count 是-------------------", count)
		if count < pageSize { //数据不足
			nGames := make([]model.Game, 0)
			err := db.MysqlEngine.SQL("select * from game where status=? and is_recommend=? order by `order` desc limit ?,?", 1, 1, 1, pageSize-count).Find(&nGames)
			if err != nil {
				fmt.Printf("GetGamesByPage err:%+v\n", err)
			}
			for i := 0; i < len(nGames); i++ {
				games = append(games, nGames[i])
			}
		}
		nextGames := make([]model.Game, 0)
		db.MysqlEngine.SQL("select * from game where status=? and is_recommend=? order by `order` desc limit ?,?", 1, 1, nextCurPageNo, pageSize).Find(&nextGames)
		fmt.Println("nextcount 是-------------------", len(nextGames))
		if len(nextGames) > 0 {
			hasMore = 1
		}
	} else {
		err := db.MysqlEngine.SQL("select * from game where status=? and category=? order by `order` desc limit ?,?", 1, aType, curPageNo, pageSize).Find(&games)
		if err != nil {
			fmt.Printf("GetGamesByPage err:%+v\n", err)
		}
		count := len(games)
		if count < pageSize { //数据不足
			nGames := make([]model.Game, 0)
			err := db.MysqlEngine.SQL("select * from game where status=? and category=? order by `order` desc limit ?,?", 1, aType, curPageNo, pageSize).Find(&nGames)
			if err != nil {
				fmt.Printf("GetGamesByPage err:%+v\n", err)
			}
			for i := 0; i < len(nGames); i++ {
				games = append(games, nGames[i])
			}
		}
		nextGames := make([]model.Game, 0)
		db.MysqlEngine.SQL("select * from game where status=? and category=? order by `order` desc limit ?,?", 1, aType, nextCurPageNo, pageSize).Find(&nextGames)
		if len(nextGames) > 0 {
			hasMore = 1
		}
	}
	for i := 0; i < len(games); i++ {
		games[i].Icon = utils.AddPrefix(games[i].Icon)
	}
	return games, hasMore
}

func GetCategoryGames() []CateGames {
	result := []CateGames{}
	categorys := []model.Categorys{}
	err := db.MysqlEngine.Where("is_show=?", 1).Desc("order").Find(&categorys)
	if err != nil {
		fmt.Printf("Get categorys err:%+v\n", err)
	}
	for i := 0; i < len(categorys); i++ {
		curCate := CateGames{}
		curCate.Id = categorys[i].Id
		curCate.Name = categorys[i].Desc
		curCate.Icon = utils.AddPrefix(categorys[i].Icon)
		games := make([]model.Game, 0)
		err := db.MysqlEngine.Join("INNER", "game_categorys", "game.id = game_categorys.gid").Where("game_categorys.cid=?", categorys[i].Id).Limit(4, 0).Desc("game.order").Find(&games)
		if err != nil {
			fmt.Printf("Get game err:%+v\n", err)
		}
		curCate.Games = games
		result = append(result, curCate)
	}
	return result
}

func GetMoreCategory(cid int) []model.Game {
	games := make([]model.Game, 0)
	err := db.MysqlEngine.Join("INNER", "game_categorys", "game.id = game_categorys.gid").Where("game_categorys.cid=?", cid).Desc("game.order").Find(&games)
	if err != nil {
		fmt.Printf("Get game err:%+v\n", err)
	}
	return games
}

/**
 @description 获取邀请人的红包游戏
 */
func GetFriendGames(plat int, userId int64) []model.Game {
	games := make([]model.Game, 0)
	err := db.MysqlEngine.Join("INNER", "user_games", "game.id = user_games.game_id").Where("user_games.user_id = ? and game.status = ?", userId, 1).In("platform", []int{0, plat}).Desc("game.order").Find(&games)
	if err != nil {
		fmt.Printf("GetFriendGames err : %s", err)
	}
	for i := 0; i < len(games); i++ {
		games[i].Icon = utils.AddPrefix(games[i].Icon)
		games[i].InviterEarn = utils.Decimal(games[i].Price * 0.3)
		games[i].PlayerEarn = utils.Decimal(games[i].Price * 0.1)
		games[i].Played = db.Mgo.UserIdValidate(userId, games[i].GameId)
	}
	return games
}

/**
 @description 通过sdk token记录游玩，及奖励
 @return
 @author guxiang
 @version v1 2018-11-24
 */
func PlaySdkGame(user *model.User, appId, openId, gameId, shareToken string) *utils.ErrorType {
	game := model.GetGameByGameId(gameId)
	if game == nil {
		return consts.ErrInvalidGameId
	}
	isValid := db.Mgo.OpenIdValidate(openId, gameId)
	if isValid { //用户已经领取过奖励
		return consts.ErrInvalidSdkUser
	}
	if shareToken != "" { //点击分享的游戏
		reInt, shareStruct := ValidateShareToken(shareToken)
		if reInt != 0 {
			if shareStruct.UserId == user.Id { //分享与点击是同一个人
				return consts.ErrInvalidSdkUser
			}
			uGame := model.UserGames{}
			has, _ := db.MysqlEngine.Where("game_id=? and user_id=?", game.Id, shareStruct.UserId).Get(&uGame)
			if has {
				//领取奖励
				ReceiveReward(user.Id, shareStruct.UserId, game.Price)
				db.Mgo.SdkRewardLog(shareStruct.UserId, user.Id, user.HeadImgUrl, user.NickName, openId, gameId, game.Name, game.Price*0.3, game.Price*0.1, time.Now().Unix(), appId, user.FromChannel)
				//记录有效点击次数
				db.Mgo.RecordPlayDetail(user.Id, user.FromChannel, gameId)
				//记录金币来源
				db.Mgo.WriteCoinsLog(shareStruct.UserId, CONINS_EARN_COLLECT, user.NickName, game.Name, user.NickName+"体验游戏"+game.Name, utils.Decimal(game.Price*0.3))
				db.Mgo.WriteCoinsLog(user.Id, CONINS_EARN_COLLECT, user.NickName, game.Name, user.NickName+"体验游戏"+game.Name, utils.Decimal(game.Price*0.1))
			} else {
				if game.Special == 1 { //特价促销游戏
					//领取奖励
					ReceiveReward(user.Id, shareStruct.UserId, game.Price)
					db.Mgo.SdkRewardLog(shareStruct.UserId, user.Id, user.HeadImgUrl, user.NickName, openId, gameId, game.Name, game.Price*0.3, game.Price*0.1, time.Now().Unix(), appId, user.FromChannel)
					//记录有效点击次数
					db.Mgo.RecordPlayDetail(user.Id, user.FromChannel, gameId)
					//记录金币来源
					db.Mgo.WriteCoinsLog(shareStruct.UserId, CONINS_EARN_COLLECT, user.NickName, game.Name, user.NickName+"体验游戏"+game.Name, utils.Decimal(game.Price*0.3))
					db.Mgo.WriteCoinsLog(user.Id, CONINS_EARN_COLLECT, user.NickName, game.Name, user.NickName+"体验游戏"+game.Name, utils.Decimal(game.Price*0.1))
				} else {
					return consts.ErrUnPayGame
				}
			}
		} else {
			return consts.ErrInvalidShareToken
		}
	}
	return nil
}

func ReceiveReward(playerId, inviterId int64, price float64) (err error) {
	if inviterId != 0 { //有推荐人
		_, err = db.MysqlEngine.Exec("update user_extra set balance = balance + ?, accum_balance = accum_balance + ? where user_id = ?", price*0.1, price*0.1, playerId)
		if err != nil {
			fmt.Printf("Add playerId balance err:", err)
		}
		_, err = db.MysqlEngine.Exec("update user_extra set balance = balance + ?, accum_balance = accum_balance + ?, accum_promote = accum_promote + ? where user_id = ?", price*0.3, price*0.3, 1, inviterId)
		if err != nil {
			fmt.Printf("Add inviterId balance err:", err)
		}
		//记录离线期间收益累积数
		AccumCoins(inviterId, price*0.3)
	}
	return
}

//获得抽奖券奖励
func ReceiveCoupon(user *model.User, goods *model.Goods, number int64) error {
	//生成券码
	generateCoupon(user.Id, goods.Id, int(number), 3)
	cgl := new(model.UserGoodsLog)
	has, err := db.MysqlEngine.Where("user_id=? and goods_id=?", user.Id, goods.Id).Get(cgl)
	fmt.Printf("----------ReceiveCoupon cgl has: %v+  err: %s", has, err)
	if !has && err == nil {
		if goods.LimitPeople-goods.CurPeople == 1 { //人满开奖
			go func() {
				GeneratePrize(goods)
			}()
			goods.CurPeople += 1
			goods.CouponStatus = 1
			goods.CouponAt = time.Now().Unix()
		} else { //普通记录人数
			goods.CurPeople += 1
		}
		if _, err := goods.Update(); err != nil {
			fmt.Printf("-----[JoinCoupon] err: %s", err)
		}
	}
	//记录投注
	RecordUserCoupon(user, goods, number)
	return nil
}

//奖励券码
func ReceiveNormalCoupon(user *model.User, gameId string) error {
	game := model.GetGameByGameId(gameId)
	if game != nil {
		number := game.Reward
		_, err := db.MysqlEngine.Exec("update user_extra set coupon = coupon + ? where user_id = ?", number, user.Id)
		if err != nil {
			fmt.Printf("-----[ReceiveNormalCoupon] err: %s", err)
		}
	}
	return nil
}

func GetGameRewardList(userId int64, gameId string) []db.SdkUserReward {
	rewardList := db.Mgo.GetGameRewardList(userId, gameId)
	for i := 0; i < len(rewardList); i++ {
		rewardList[i].InviterEarn = utils.CutDecimal(rewardList[i].InviterEarn)
		rewardList[i].FormatDate = utils.FormatDate(rewardList[i].DateTime)
	}
	return rewardList
}

func GetSpecialGames(gameId string, userId int64) []model.Game {
	games := make([]model.Game, 0)
	box := new(model.Box)
	_, err := db.MysqlEngine.Where("name = ?", gameId).Get(box)
	if err != nil || box == nil {
		fmt.Printf("Get box err ---------%v", err)
		return games
	}
	ids := []int64{}
	gameBox := make([]model.GameBox, 0)
	err = db.MysqlEngine.Where("box_id=?", box.Id).Find(&gameBox)
	if err != nil || len(gameBox) < 1 {
		fmt.Printf("Get gamebox err ---------%v", err)
		return games
	} else {
		for i := 0; i < len(gameBox); i++ {
			ids = append(ids, gameBox[i].GameId)
		}
	}
	err = db.MysqlEngine.Where("status=? and special=?", 1, 1).In("id", ids).Find(&games)
	if err != nil {
		fmt.Printf("GetGameList err:%+v\n", err)
	}
	for i := 0; i < len(games); i++ {
		games[i].CateName = GetGameCategory(games[i])
		games[i].Icon = utils.AddPrefix(games[i].Icon)
		games[i].InviterEarn = utils.Decimal(games[i].Price * 0.3)
		games[i].PlayerEarn = utils.Decimal(games[i].Price * 0.1)
		games[i].PromoteUser = CalculatePromote(games[i].GameId, userId)
		games[i].PromoteNumber = len(games[i].PromoteUser)
		games[i].Played = db.Mgo.UserIdValidate(userId, games[i].GameId)
		games[i].Earning = CalculateEarning(games[i].GameId, userId)
	}
	return games
}

//获取未体验过的游戏
func GetUnusedGame(user *model.User, gameId string) *model.Game {
	box := new(model.Box)
	_, err := db.MysqlEngine.Where("name = ?", gameId).Get(box)
	if err != nil || box == nil {
		fmt.Printf("Get box err ---------%v", err)
		return nil
	}
	ids := []int64{}
	gameBox := make([]model.GameBox, 0)
	err = db.MysqlEngine.Where("box_id=?", box.Id).Find(&gameBox)
	if err != nil || len(gameBox) < 1 {
		fmt.Printf("Get gamebox err ---------%v", err)
		return nil
	} else {
		for i := 0; i < len(gameBox); i++ {
			ids = append(ids, gameBox[i].GameId)
		}
	}
	games := db.Mgo.GetUserGameLog(user.Id)
	game := make([]model.Game, 0)
	err = db.MysqlEngine.In("id", ids).Where("status=?", 1).Find(&game)
	if err != nil {
		fmt.Printf("-----[GetUnusedGame] err: %s", err)
	}
	if len(game) > 0 {
		for i := 0; i < len(game); i++ {
			if !utils.StringInSlice(games, game[i].GameId) {
				game[i].QrCode = utils.AddPrefix(game[i].QrCode)
				game[i].Cover = utils.AddPrefix(game[i].Cover)
				game[i].Icon = utils.AddPrefix(game[i].Icon)
				return &game[i]
			}
		}
	}
	return nil
}
